package com.health.config;

import com.health.security.CustomLogoutSuccessHandler;
import com.health.security.SpringSecurityUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

/**
 * @Classname SecurityConfig
 * @Description TODO
 * @Version 1.0.0
 * @Date 2023/3/28 10:19
 * @Author RainGrd
 */
@Configuration
@EnableWebSecurity
//prePostEnabled属性决定Spring Security在接口前注解是否可用@PreAuthorize,@PostAuthorize等注解,设置为true,会拦截加了这些注解的接口
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    /*@Resource
    private AuthenticationSuccessHandler loginSuccessHandler; //认证成功结果处理器
    @Resource
    private AuthenticationFailureHandler loginFailureHandler; //认证失败结果处理器*/

    @Autowired
    protected SpringSecurityUserService userService;

    /**
     * 指定加密方式
     */
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        // 使用BCrypt加密密码
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 设置自定义的userDetailsService
        auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //开启运行iframe嵌套页面
        http.headers().frameOptions().disable();
        //配置权限
        http.authorizeRequests()
                .antMatchers("/login.do").permitAll()
                .antMatchers("/login.html").permitAll()
//                .antMatchers("/css/**").permitAll()
                .anyRequest() //任何其它请求
                .authenticated() //都需要身份认证
                .and()
                //2、登录配置表单认证方式
                .formLogin()
                .loginPage("/login.html")//自定义登录页面的url
                .usernameParameter("username")//设置登录账号参数，与表单参数一致
                .passwordParameter("password")//设置登录密码参数，与表单参数一致
                // 告诉Spring Security在发送指定路径时处理提交的凭证，默认情况下，将用户重定向回用户来自的页面。登录表单form中action的地址，也就是处理认证请求的路径，
                // 只要保持表单中action和HttpSecurity里配置的loginProcessingUrl一致就可以了，也不用自己去处理，它不会将请求传递给Spring MVC和您的控制器，所以我们就不需要自己再去写一个/user/login的控制器接口了
                .loginProcessingUrl("/login.do")//配置默认登录入口
                .defaultSuccessUrl("/pages/main.html")//登录成功后默认的跳转页面路径
                .failureUrl("/login.html")
                //.successHandler(loginSuccessHandler)//使用自定义的成功结果处理器
                //.failureHandler(loginFailureHandler)//使用自定义失败的结果处理器
                .and()
                //3、注销
                .logout()
                .logoutUrl("/logout.do")
                .logoutSuccessHandler(new CustomLogoutSuccessHandler())
                //注销session
                .invalidateHttpSession(true)
                .permitAll()
                .and()
                //4、session管理
                .sessionManagement()
                .invalidSessionUrl("/login.html") //失效后跳转到登陆页面
                //单用户登录，如果有一个登录了，同一个用户在其他地方登录将前一个剔除下线
                //.maximumSessions(1).expiredSessionStrategy(expiredSessionStrategy())
                //单用户登录，如果有一个登录了，同一个用户在其他地方不能登录
                //.maximumSessions(1).maxSessionsPreventsLogin(true) ;
                .and()
                //5.禁用跨站csrf攻击防御
                .csrf()
                .disable();
    }



    @Override
    public void configure(WebSecurity web) throws Exception {
        //配置静态文件不需要认证
        web.ignoring().antMatchers(
                "/css/**",
                "/js/**",
                "/img/**",
                "/plugins/**",
                "/upload/**",
                "/template/**");
    }

}
